package com.xyhy.starter.mfx.service;

import cn.hutool.core.lang.func.Func1;
import cn.hutool.core.lang.func.LambdaUtil;
import cn.hutool.core.util.ReflectUtil;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import com.xyhy.core.utils.jdk.StreamUtil;
import com.xyhy.starter.mfx.entity.IId;
import com.xyhy.starter.mfx.repostory.MfxRepository;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

public abstract class MfxService<T extends IId<ID>, ID, REPOS extends MfxRepository<T, ID>> {
  @Getter
  protected @Autowired REPOS repos;

  public T findValidOne(ID id) {
    return repos.findValidOne(id);
  }

  public T findByIdOrNull(ID id) {
    return repos.findByIdOrNull(id);
  }

  public Optional<T> findById(ID id) {
    return repos.findById(id);
  }

  public List<T> findAllById(List<ID> ids) {
    return repos.findAllById(ids);
  }

  public List<T> findAllByIdInOrder(List<ID> ids) {
    return repos.findAllByIdInOrder(ids);
  }

  public Map<ID, T> getMap(List<ID> ids) {
    List<T> data = repos.findAllById(ids);
    return StreamUtil.toMap(data, x -> x.getId(), Function.identity());
  }

  public <U> Map<ID, T> getMap(Collection<U> data, Function<U, ID> idGetter) {
    List<ID> ids = StreamUtil.toDistinctList(data, idGetter);
    List<T> tData = repos.findAllById(ids);
    return StreamUtil.toMap(tData, x -> x.getId(), Function.identity());
  }

  public String getName(ID id) {
    return repos.findById(id).map(x -> getName(x)).orElse(null);
  }

  public Map<ID, String> getNameMap(List<ID> ids) {
    return repos.findAllById(ids).stream().collect(Collectors.toMap(x -> x.getId(), x -> getName(x)));
  }

  public <U> void fillName(List<U> data, Function<U, ID> idGetter, BiConsumer<U, String> consumer) {
    List<ID> ids = StreamUtil.toDistinctList(data, idGetter);
    Map<ID, String> nameMap = getNameMap(ids);
    data.forEach(x -> consumer.accept(x, nameMap.get(idGetter.apply(x))));
  }

  public <U> void fillName(List<U> data, Function<U, ID> idGetter, Func1<U, String> setter) {
    String fieldName = LambdaUtil.getFieldName(setter);
    fillName(data, idGetter, (x, y) -> ReflectUtil.setFieldValue(x, fieldName, y));
  }

  protected String getName(T t) {
    return Optional.ofNullable(ReflectUtil.getFieldValue(t, "name")).map(x -> x.toString()).orElse(null);
  }


}
